package MULE.Model;

import java.util.EnumSet;
import java.util.HashMap;

/**
 * Represents an inventory that can store money and resources.
 * 
 * @author jstep
 */
public class Inventory implements java.io.Serializable {

	/**
	 * Serial version UID.
	 */
	private static final long serialVersionUID = 2262336526907027679L;

	private HashMap<Resource, Integer> inventory;

	/**
	 * Instantiates a new Inventory with zero resources.
	 */
	public Inventory() {
		this(0, 0, 0, 0, 0);
	}

	/**
	 * Instantiates a new Inventory with specified resources.
	 * 
	 * @param money
	 *            Initial amount of money.
	 * @param food
	 *            Initial amount of food.
	 * @param energy
	 *            Initial amount of energy.
	 * @param smithore
	 *            Initial amount of smithore.
	 * @param crystite
	 *            Initial amount of crystite.
	 */
	public Inventory(int money, int food, int energy, int smithore, int crystite) {
		this.inventory = new HashMap<Resource, Integer>();
		inventory.put(Resource.MONEY, money);
		inventory.put(Resource.FOOD, food);
		inventory.put(Resource.ENERGY, energy);
		inventory.put(Resource.SMITHORE, smithore);
		inventory.put(Resource.CRYSTITE, crystite);
		inventory.put(Resource.MULE, 0);
	}

	/**
	 * Adds specified amount of resource to this inventory.
	 * 
	 * @param type
	 *            Type of resource as defined in Inventory.Resource.
	 * @param amount
	 *            Amount of resource to add.
	 */
	public void add(Resource type, int amount) {
		int currentAmount = inventory.get(type);
		int newAmount = currentAmount + amount;
		inventory.put(type, newAmount);
	}

	/**
	 * Adds the given resources to this inventory.
	 * 
	 * @param resources
	 *            Resources to add to this inventory.
	 */
	public void add(Inventory resources) {
		// Add each resource type individually.
		for (Resource type : EnumSet.allOf(Resource.class)) {
			this.add(type, resources.getAmount(type));
		}
	}

	/**
	 * Subtracts specified amount of resource from this inventory.
	 * 
	 * @param type
	 *            Type of resource as defined in Inventory.Resource
	 * @param amount
	 *            Amount of resource to subtract.
	 */
	public void subtract(Resource type, int amount) {
		int currentAmount = inventory.get(type);
		int newAmount = currentAmount - amount;
		inventory.put(type, newAmount);
	}

	/**
	 * Subtracts the given resources from this inventory.
	 * 
	 * @param resources
	 *            Resources to subtract from this inventory.
	 */
	public void subtract(Inventory resources) {
		// Add each resource type individually.
		for (Resource type : EnumSet.allOf(Resource.class)) {
			this.subtract(type, resources.getAmount(type));
		}
	}

	/**
	 * Multiplies by specified amount of resource to this inventory.
	 * 
	 * @param type
	 *            Type of resource as defined in Inventory.
	 * @param amount
	 *            Amount to multiply by.
	 */
	public void multiply(Resource type, int amount) {
		int currentAmount = inventory.get(type);
		int newAmount = currentAmount * amount;
		inventory.put(type, newAmount);
	}

	/**
	 * Multiply the given resources from this inventory.
	 * 
	 * @param resources
	 *            Resources to multiply from this inventory.
	 */

	public void multiply(int amount) {
		// multiply each resource type individually.
		for (Resource type : EnumSet.allOf(Resource.class)) {
			this.multiply(type, amount);
		}
	}

	/**
	 * Returns the amount of specified resource in this inventory.
	 * 
	 * @param type
	 *            Resource type in question.
	 * @return Amount of specified resource.
	 */
	public int getAmount(Resource type) {
		return inventory.get(type);
	}

	/**
	 * Checks if this inventory has at least the same amount of resources as the
	 * given inventory.
	 * 
	 * @param resources
	 *            The resources to compare this inventory to.
	 * @return True if this inventory has at least the amount of given
	 *         resources, false otherwise.
	 */
	public boolean hasResources(Inventory resources) {
		// Compare each resource type individually.
		for (Resource type : EnumSet.allOf(Resource.class)) {
			if (this.getAmount(type) < resources.getAmount(type)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Returns the total assets of this inventory. Total assets are calculated
	 * by adding summing value of all resources.
	 * 
	 * @return Total assets in this inventory.
	 */
	public int getTotalAssets() {
		int totalAssets = 0;
		// Add each resource value.
		for (Resource resource : EnumSet.allOf(Resource.class)) {
			totalAssets += resource.getValue() * getAmount(resource);
		}
		return totalAssets;
	}

	/**
	 * Returns a string representation of this inventory.
	 * 
	 * @return String representation of this inventory.
	 */
	public String toString() {
		String description = "";
		// Compare each resource type individually.
		for (Resource type : EnumSet.allOf(Resource.class)) {
			description += type.toString() + ":";
			description += this.getAmount(type) + ", ";
		}
		return description;
	}

	/**
	 * Removes any mules from this inventory.
	 */
	public void removeMule() {
		this.inventory.put(Resource.MULE, 0);
	}
}
